import { VNodeProps, createVNode, ref, render } from "vue";
import { RouteRecordRaw } from "vue-router";
import {
    MyTypeComponentClass,
    TypeRouteRecordRawWithFullPath,
} from "./util_type";
import { resolve } from "path-browserify";


type Data = {
    [x: string]: unknown;
};

/**
 *
 * @param globPath 根据传入的globPath，获取<path,component>的map,其中component已经解析，可以直接使用
 * @returns
 */
async function getPathComponentMap(
    globModules: Record<string, () => Promise<unknown>>
) {
    const promiseArray = [];
    const pathArray = [];

    for (const path in globModules) {
        pathArray.push(path);
        promiseArray.push(globModules[path]());
        // console.log('path =',path);
        // console.log('globModules[path] =',globModules[path]);
        
    }
    let modulesResolved;
    try {
        modulesResolved = await Promise.all(promiseArray);
    } catch (error) {
        throw new Error("获取组件模块失败");
    }

    const pathComponentMap = new Map<string, MyTypeComponentClass>();
    pathArray.forEach((e, index) => {
        const moduleTmp: any = modulesResolved[index];
        pathComponentMap.set(e, moduleTmp.default);
    });
    return pathComponentMap;
}
/**
 * 对import.meta.glob的导入的vue文件,根据关键词数组，生成用于 router的 RouteRecordRaw[]
 * @param globModules import.meta.glob('@/components/xxx/xxx_test.vue') 结果，因为import.meta.glob 不能使用变量
 * @param componentNameFilterArray component文件名 关键词 数组，用于筛序
 * @returns
 */
async function createRoutesArray(
    globModules: Record<string, () => Promise<unknown>>,
    componentNameFilterArray: string[]
): Promise<RouteRecordRaw[]> {
    const pathComponentMap = await NslUtil4Vue.getPathComponentMap(globModules);
    const filteredRoutes = componentNameFilterArray
        .map((componentName) => {
            const keys = pathComponentMap.keys();
            // console.log('keys',keys);
            // console.log('componentName=',componentName);
            for (let key of keys) {
                // console.log('componentName=',componentName);
                // console.log('key=',key)
                if (key.includes(componentName)) {
                    return {
                        name: componentName,
                        path: componentName,
                        component: pathComponentMap.get(
                            key
                        ) as MyTypeComponentClass,
                        meta: {
                            title: componentName,
                        },
                    };
                }
            }
        })
        .filter((e) => e); //去掉undefined
    //@ts-expect-error  感觉ts 类型推断错误
    return filteredRoutes;
}

/**
 * 根据component配置对象和props，绘制dom元素,
 * 其中myUnmounted函数作用：卸载元素和组件对象
 * @param componentConstructor
 * @param props
 * @returns
 */
export function renderComponent(
    componentConstructor: MyTypeComponentClass,
    props: (Data & VNodeProps) | null
) {
    const container = document.createElement("div");
    const vnode = createVNode(componentConstructor, props, null);
    render(vnode, container);

    const myUnmounted = () => render(null, container);
    return {
        ...vnode.component,
        myUnmounted,
    };
}
/**
 * 根据组件配置对象，生成组件配置对象实例的ref
 * @param _comp  组件配置对象，即Component，如ElButton
 * @returns
 */
function componentRef<T extends abstract new (...args: any) => any>(_comp: T) {
    return ref<InstanceType<T>>();
}



/**
 * 根据传入的routeRecord[]，生成增加了fullpath的routeRecord[]
 * @param routes routeRecord[]
 * @param basePath 使用默认值，不传参
 * @returns 
 */
function buildFullPathRoutes(routes: RouteRecordRaw[], basePath: string = "/"):TypeRouteRecordRawWithFullPath[] {
    const fullPathRoutes = routes.map((r) => ({
        ...r,
        fullPath: resolve(basePath, r.path),
    }));

    fullPathRoutes.forEach((r) => {
        if (r.children) {
            r.children=buildFullPathRoutes(r.children, r.fullPath);
        }
    });
    return fullPathRoutes;
}





const NslUtil4Vue = {
    getPathComponentMap,
    renderComponent,
    createRoutesArray,
    componentRef,
    buildFullPathRoutes
};

export { NslUtil4Vue };
